home *** CD-ROM | disk | FTP | other *** search
- #!/usr/freeware/bin/expect --
- # Name: autoexpect - generate an Expect script from watching a session
- #
- # Description:
- #
- # Given a program name, autoexpect will run that program. Otherwise
- # autoexpect will start a shell. Interact as desired. When done, exit
- # the program or shell. Autoexpect will create a script that reproduces
- # your interactions. By default, the script is named script.exp.
- # See the man page for more info.
- #
- # Author: Don Libes, NIST
- # Date: June 30 1995
- # Version: 1.4b
-
- set filename "script.exp"
- set verbose 1
- set conservative 0
- set promptmode 0
- set option_keys ""
-
- proc check_for_following {type} {
- if ![llength [uplevel set argv]] {
- puts "autoexpect: [uplevel set flag] requires following $type"
- exit 1
- }
- }
-
- while {[llength $argv]>0} {
- set flag [lindex $argv 0]
- if 0==[regexp "^-" $flag] break
- set argv [lrange $argv 1 end]
- switch -- $flag \
- "-c" {
- set conservative 1
- } "-C" {
- check_for_following character
- lappend option_keys [lindex $argv 0] ctoggle
- set argv [lrange $argv 1 end]
- } "-p" {
- set promptmode 1
- } "-P" {
- check_for_following character
- lappend option_keys [lindex $argv 0] ptoggle
- set argv [lrange $argv 1 end]
- } "-Q" {
- check_for_following character
- lappend option_keys [lindex $argv 0] quote
- set argv [lrange $argv 1 end]
- } "-f" {
- check_for_following filename
- set filename [lindex $argv 0]
- set argv [lrange $argv 1 end]
- } "-quiet" {
- set verbose 0
- } default {
- break
- }
- }
-
- #############################################################
- # Variables Descriptions
- #############################################################
- # userbuf buffered characters from user
- # procbuf buffered characters from process
- # lastkey last key pressed by user
- # if undefined, last key came from process
- # echoing if the process is echoing
- #############################################################
-
- # Handle a character that came from user input (i.e., the keyboard)
- proc input {c} {
- global userbuf lastkey
-
- send -- $c
- append userbuf $lastkey
- set lastkey $c
- }
-
- # Handle a null character from the keyboard
- proc input_null {} {
- global lastkey userbuf procbuf echoing
-
- send -null
-
- if {$lastkey == ""} {
- if $echoing {
- sendcmd "$userbuf"
- }
- if {$procbuf != ""} {
- expcmd "$procbuf"
- }
- } else {
- sendcmd "$userbuf"
- if $echoing {
- expcmd "$procbuf"
- sendcmd "$lastkey"
- }
- }
- cmd "send -null"
- set userbuf ""
- set procbuf ""
- set lastkey ""
- set echoing 0
- }
-
- # Handle a character that came from the process
- proc output {s} {
- global lastkey procbuf userbuf echoing
-
- send_user -raw -- $s
-
- if {$lastkey == ""} {
- if !$echoing {
- append procbuf $s
- } else {
- sendcmd "$userbuf"
- expcmd "$procbuf"
- set echoing 0
- set userbuf ""
- set procbuf $s
- }
- return
- }
-
- regexp (.)(.*) $s dummy c tail
- if {$c == $lastkey} {
- if $echoing {
- append userbuf $lastkey
- set lastkey ""
- } else {
- if {$procbuf != ""} {
- expcmd "$procbuf"
- set procbuf ""
- }
- set echoing 1
- }
- append procbuf $s
-
- if [string length $tail] {
- sendcmd "$userbuf$lastkey"
- set userbuf ""
- set lastkey ""
- set echoing 0
- }
- } else {
- if !$echoing {
- expcmd "$procbuf"
- }
- sendcmd "$userbuf$lastkey"
- set procbuf $s
- set userbuf ""
- set lastkey ""
- set echoing 0
- }
- }
-
- # rewrite raw strings so that can appear as source code but still reproduce
- # themselves.
- proc expand {s} {
- regsub -all "\\\\" $s "\\\\\\\\" s
- regsub -all "\r" $s "\\r" s
- regsub -all "\"" $s "\\\"" s
- regsub -all "\\\[" $s "\\\[" s
- regsub -all "\\\]" $s "\\\]" s
- regsub -all "\\\$" $s "\\\$" s
-
- return $s
- }
-
- # generate an expect command
- proc expcmd {s} {
- global promptmode
-
- if $promptmode {
- regexp ".*\[\r\n]+(.*)" $s dummy s
- }
-
- cmd "expect -exact \"[expand $s]\""
- }
-
- # generate a send command
- proc sendcmd {s} {
- global send_style conservative
-
- if {$conservative} {
- cmd "sleep .1"
- }
-
- cmd "send$send_style -- \"[expand $s]\""
- }
-
- # generate any command
- proc cmd {s} {
- global fd
- puts $fd "$s"
- }
-
- proc verbose_send_user {s} {
- global verbose
-
- if $verbose {
- send_user -- $s
- }
- }
-
- proc ctoggle {} {
- global conservative send_style
-
- if $conservative {
- cmd "# conservative mode off - adding no delays"
- verbose_send_user "conservative mode off\n"
- set conservative 0
- set send_style ""
- } else {
- cmd "# prompt mode on - adding delays"
- verbose_send_user "conservative mode on\n"
- set conservative 1
- set send_style " -s"
- }
- }
-
- proc ptoggle {} {
- global promptmode
-
- if $promptmode {
- cmd "# prompt mode off - now looking for complete output"
- verbose_send_user "prompt mode off\n"
- set promptmode 0
- } else {
- cmd "# prompt mode on - now looking only for prompts"
- verbose_send_user "prompt mode on\n"
- set promptmode 1
- }
- }
-
- # quote the next character from the user
- proc quote {} {
- expect_user -re .
- send -- $expect_out(buffer)
- }
-
-
- if [catch {set fd [open $filename w]} msg] {
- puts $msg
- exit
- }
- exec chmod +x $filename
- verbose_send_user "autoexpect started, file is $filename\n"
-
- # calculate a reasonable #! line
- set expectpath /usr/local/bin ;# prepare default
- foreach dir [split $env(PATH) :] { ;# now look for real location
- if [file executable $dir/expect] {
- set expectpath $dir
- break
- }
- }
-
- cmd "#![set expectpath]/expect -f
- #
- # This Expect script was generated by autoexpect on [timestamp -format %c]
- # Expect and autoexpect were both written by Don Libes, NIST."
- cmd {#
- # Note that autoexpect does not guarantee a working script. It
- # necessarily has to guess about certain things. Two reasons a script
- # might fail are:
- #
- # 1) timing - A surprising number of programs (rn, ksh, zsh, telnet,
- # etc.) and devices discard or ignore keystrokes that arrive "too
- # quickly" after prompts. If you find your new script hanging up at
- # one spot, try adding a short sleep just before the previous send.
- # Setting "force_conservative" to 1 (see below) makes Expect do this
- # automatically - pausing briefly before sending each character. This
- # pacifies every program I know of. The -c flag makes the script do
- # this in the first place. The -C flag allows you to define a
- # character to toggle this mode off and on.
-
- set force_conservative 0 ;# set to 1 to force conservative mode even if
- ;# script wasn't run conservatively originally
- if {$force_conservative} {
- set send_slow {1 .1}
- proc send {ignore arg} {
- sleep .1
- exp_send -s -- $arg
- }
- }
-
- #
- # 2) differing output - Some programs produce different output each time
- # they run. The "date" command is an obvious example. Another is
- # ftp, if it produces throughput statistics at the end of a file
- # transfer. If this causes a problem, delete these patterns or replace
- # them with wildcards. An alternative is to use the -p flag (for
- # "prompt") which makes Expect only look for the last line of output
- # (i.e., the prompt). The -P flag allows you to define a character to
- # toggle this mode off and on.
- #
- # Read the man page for more info.
- #
- # -Don
-
- }
-
- cmd "set timeout -1"
- if $conservative {
- set send_style " -s"
- cmd "set send_slow {1 .1}"
- } else {
- set send_style ""
- }
-
- if [llength $argv]>0 {
- eval spawn -noecho $argv
- cmd "spawn $argv"
- } else {
- spawn -noecho $env(SHELL)
- cmd "spawn \$env(SHELL)"
- }
-
- cmd "match_max 100000"
-
- set lastkey ""
- set procbuf ""
- set userbuf ""
- set echoing 0
-
- remove_nulls 0
-
- eval interact $option_keys {
- -re . {
- input $interact_out(0,string)
- } null {
- input_null
- } \
- -o \
- -re .+ {
- output $interact_out(0,string)
- } eof {
- cmd "expect eof"
- return
- } null {
- }
- }
-
- close $fd
- verbose_send_user "autoexpect done, file is $filename\n"
-